Intro

Electron is a tool that can code desktop APP with web technology.

it use HTML, JS and CSS to contructure the APP and any corresponding libraries you want in the ecosystem.


Windows

Each window is a separate process (独立进程), or render process.

BrowserWindow is the module to manage windows.

Location: const BrowserWindow = require('electron').remote.BrowserWindow

Create a new window

const BrowserWindow = require('electron').remote.BrowserWindow;
const path = require('path');

const newWindowBtn = document.querySelector('.home-new-btn');

newWindowBtn.addEventListener('click', event => {
  const modalPath = path.join('file://', __dirname, 'index.html');
  let win = new BrowserWindow({
    width: 400,
    height: 320,
    /* frameless window */
    //transparent: true,
    //frame: false
    /* background window */
    // show: false
  });
  win.on('close', () => win = null);
  win.loadURL(modalPath);
  win.show();
})

几个重要的步骤:

  • 创建 BrowserWindow 实例
  • 给实例指定读取的URL (loadURL)
  • 给实例创建关闭方法,释放内存
  • 显示实例

可以通过设置 show: false 来启动一个后台窗口,跑跑线程等

Event

除了上述的 close 事件,一般使用的事件还有如下:

  win.on('resize', callback)	// 调整大小
  win.on('move', callback)		// 拖动窗口
  win.on('focus', callback)		// 选中
  win.on('blur', callback)		// 失焦

Menu

Menu and MenuItem module is used to create custom native menu.

const electron = require('electron')
const Menu = electron.Menu
const app = electron.app

let menuTemplate = [
    {
      label: 'Edit',
      subMenu: [
        {
          label: Undo,
          accelerator: 'CmdOrCtrl+z',
          role: 'undo'
        },
        ...]
    },
    {
       label: 'View',
       submenu: [
        {
       	  label: 'Reload',
          accelerator: 'CmdOrCtrl+R',
          click: function(){return 'Ctrl+Shift+I'}
      	}
      ]
    }
  }
]

...

app.on('ready', function () {
  const menu = Menu.buildFromTemplate(menuTemplate)
  Menu.setApplicationMenu(menu)
})

we can also reguster a globa keyboard shortcut, see API demo.


Native Interface

###shell

we can access some system native interface through the shell module, like open file manager and open external link with default browser.

const shell = require('electron').shell
const os = require('os')
const fileManagerBtn = some DOM

fileManagerBtn.addEventListener('click', function (event) {
  // open file manager
  shell.showItemInFolder(os.homedir())
  // open website with default browser
  shell.openExternal('www.example.com')
})

###Dialogs

dialog module used to render a dialog, while ipcRenderer module is used to send a message to the renderer process instructing the main process to launch the dialog.

const ipc = require('electron').ipcRenderer
const dialog = require('electron').dialog

/*************
****open a file dialog
**************/
// in ther render process
ipc.send('open-file-dialog')
ipc.on('selected-directory', function (event, path) {
  DOM.innerHTML = 'You selected ' + path;
})

// in the main process
ipc.on('open-file-dialog', function (event) {
  dialog.showOpenDialog({
    properties: ['openFile', 'openDirectory']
  }, function (files) {
    if (files) event.sender.send('selected-directory', files)
  })
})
const ipc = require('electron').ipcRenderer
const dialog = require('electron').dialog

/*************
****show error message
**************/
// in ther render process
ipc.send('open-error-dialog')

// in the main process
ipc.on('open-error-dialog', function (event) {
	dialog.showErrorBox('An Error Message', 'Demonstrating an error message.')
})
const ipc = require('electron').ipcRenderer
const dialog = require('electron').dialog

/*************
****make choice in dialog
**************/
// in ther render process
ipc.send('open-information-dialog')
ipc.on('information-dialog-selection', function (event, index) {
  let message = 'You selected '
  if (index === 0) message += 'yes.'
  else message += 'no.'
  DOM.innerHTML = message
})

// in the main process
ipc.on('open-information-dialog', function (event) {
  const options = {
    type: 'info',
    title: 'Information',
    message: "This is an information dialog. Isn't it nice?",
    buttons: ['Yes', 'No']
  }
  dialog.showMessageBox(options, function (index) {
    event.sender.send('information-dialog-selection', index)
  })
})
const ipc = require('electron').ipcRenderer
const dialog = require('electron').dialog

/*************
****save file dialog
**************/
// in ther render process
ipc.send('save-dialog')
ipc.on('saved-file', function (event, path) {
  if (!path) path = 'No path'
  DOM.innerHTML = `Path selected: ${path}`
})

// in the main process
ipc.on('save-dialog', function (event) {
  const options = {
    title: 'Save an Image',
    filters: [
      { name: 'Images', extensions: ['jpg', 'png', 'gif'] }
    ]
  }
  dialog.showSaveDialog(options, function (filename) {
    event.sender.send('saved-file', filename)
  })
})

Tray

tray module is used to show an icon on the OS notification bar.


IPC

inter-process commnunication allow us to communicate between renderer process ipcRenderer and main process ipcMain by sending message.